﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.IO;
using System.Drawing.Drawing2D;

namespace Qiang.Data
{
    [Serializable]
    public class ImageDataset : Dataset,IImageDataset
    {
        # region 构造

        public ImageDataset()
        { 

        }

        public ImageDataset(string fileName)
        {
            this._fileName = fileName;
            this.Open();
        }

        # endregion

        # region 属性

        private string _fileName;

        /// <summary>
        /// 位图路径
        /// </summary>
        public string FileName
        {
            get { return _fileName; }
            set { _fileName = value; }
        }

        private Bitmap _innerImage;

        /// <summary>
        /// 位图数据
        /// </summary>
        public Bitmap InnerImage
        {
            get { return _innerImage; }
            set { _innerImage = value; }
        }


        private ImageBandType _bandType;

        /// <summary>
        /// 位图波段类型
        /// </summary>
        public ImageBandType BandType
        {
            get { return _bandType; }
            set { _bandType = value; }
        }
        

        private WorldFile _worldFile;

        /// <summary>
        /// 位图坐标信息
        /// </summary>
        public WorldFile WorldFile
        {
            get { return _worldFile; }
            set { _worldFile = value; }
        }


        private double _width;

        /// <summary>
        /// 位图可能经过旋转偏移等等操做
        /// 这里是指位图在坐标体系下的真实宽度
        /// </summary>
        public double Width
        {
            get 
            {
                this._width = this._pixelWidth * Math.Abs( this._worldFile.Affine[1]) + this._pixelHeight * Math.Abs( this._worldFile.Affine[2]);
                return _width; 
            }
            set { _width = value; }
        }

        private double _height;

        /// <summary>
        /// 位图可能经过旋转偏移等等操做
        /// 这里是指位图在坐标体系下的真实高度
        /// </summary>
        public double Height
        {
            get 
            {
                this._height = this._pixelHeight *Math.Abs ( this._worldFile.Affine[5]) + this._pixelWidth *Math .Abs ( this._worldFile.Affine[4]);
                return _height;
            }
            set { _height = value; }
        }


        private double _leftX;

        /// <summary>
        /// 位图可能经过旋转偏移等等操做
        /// 这里是指位图在坐标体系下的最小X坐标
        /// </summary>
        public double LeftX
        {
            get
            {
                this._leftX = double.MaxValue;
                //世界文件的左上角坐标
                if (this._worldFile.Affine[0] < this._leftX) this._leftX = this._worldFile.Affine[0];
                //如果世界文件x方向的间距是负的，则位图的显示在X方向是反向的
                if (this._worldFile.Affine[0] + this._pixelWidth * this._worldFile.Affine[1] < this._leftX) this._leftX = this._worldFile.Affine[0] + this._pixelWidth * this._worldFile.Affine[1];
                //Y方向的切变也有可能导致位图X方向的视觉变化，使位图在X方向反向
                if (this._worldFile.Affine[0] + this._pixelHeight * this._worldFile.Affine[2] < this._leftX) this._leftX = this._worldFile.Affine[0] + this._pixelHeight * this._worldFile.Affine[2];
                //上面两个原因的综合
                if (this._worldFile.Affine[0] + this._pixelWidth * this._worldFile.Affine[1] + this._worldFile.Affine[0] + this._pixelHeight * this._worldFile.Affine[2] < this._leftX)
                    this._leftX = this._worldFile.Affine[0] + this._pixelWidth * this._worldFile.Affine[1] + this._worldFile.Affine[0] + this._pixelHeight * this._worldFile.Affine[2];

                return _leftX;
            }
            set { _leftX = value; }
        }


        private double _upY;

        /// <summary>
        /// 位图可能经过旋转偏移等等操做
        /// 这里是指位图在坐标体系下的最大Y坐标
        /// </summary>
        public double UpY
        {
            get
            {
                this._upY = double.MinValue;
                if (this._worldFile.Affine[3] > this._upY) this._upY = this._worldFile.Affine[3];
                if (this._worldFile.Affine[3] + this._pixelHeight * this._worldFile.Affine[5] > this._upY) this._upY = this._worldFile.Affine[3] + this._pixelHeight * this._worldFile.Affine[5];
                if (this._worldFile.Affine[3] + this._pixelWidth * this._worldFile.Affine[4] > this._upY) this._upY = this._worldFile.Affine[3] + this._pixelWidth * this._worldFile.Affine[4];
                if (this._worldFile.Affine[3] + this._pixelHeight * this._worldFile.Affine[5] + this._pixelWidth * this._worldFile.Affine[4] > this._upY)
                    this._upY = this._worldFile.Affine[3] + this._pixelHeight * this._worldFile.Affine[5] + this._pixelWidth * this._worldFile.Affine[4];

                return _upY;
            }
            set { _upY = value; }
        }



        private int _pixelWidth;

        /// <summary>
        /// 位图像素宽度
        /// </summary>
        public int PixelWidth
        {
            get { return _pixelWidth; }
            set { _pixelWidth = value; }
        }


        private int _pixelHeight;

        /// <summary>
        /// 位图像素高度
        /// </summary>
        public int PixelHeight
        {
            get { return _pixelHeight; }
            set { _pixelHeight = value; }
        }


        private byte[] _values;

        /// <summary>
        /// 位图数据
        /// </summary>
        public byte[] Values
        {
            get { return _values; }
            set { _values = value; }
        }



        # endregion


        # region 受保护的方法

        protected override IExtent ComputeExtent()
        {
            if (this._worldFile == null || this._worldFile.Affine == null) return null;
            if (this._worldFile.Affine[1] == 0 || this._worldFile.Affine[5] == 0) return null;
            return new Extent(this.LeftX, this.UpY - this.Height, this.LeftX + this.Width, this.UpY);
        }

        # endregion

        # region 公共方法

        public void OpenFile(string fileName)
        {
            this._fileName = fileName;
            this.Open();
        }


        public void Open()
        {
            if (this._innerImage != null)
            {
                this._innerImage.Dispose();
            }

            //using的使用，意思是在这段代码内不管怎样是否发生异常，只要这段代码结束，using内的字段自动调用dispose方法
            //同try……catch可在catch内手动写字段的dispose方法
            using (FileStream stream = new FileStream(this._fileName, FileMode.Open))
            {
                Image tempImage = Image.FromStream(stream);
                this._innerImage = new Bitmap(tempImage.Width, tempImage.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
                this._pixelWidth = tempImage.Width;
                this._pixelHeight = tempImage.Height;
                Graphics g = Graphics.FromImage(this._innerImage);
                g.DrawImage(tempImage, new Rectangle(0, 0, tempImage.Width, tempImage.Height));
                g.Dispose();
                tempImage.Dispose();
            }

            this._worldFile = new WorldFile(this._fileName);
            if (this._worldFile.Affine == null)
                this._worldFile.Affine = new double[] { 0.5, 1.0, 0, this._innerImage.Height - 0.5, 0, -1.0 };


        }

        
        public Bitmap GetBitmap(IExtent ext,Rectangle rect)
        {
            if (ext.Width == 0 || ext.Height == 0) return null;
            if (rect.Width <= 0 || rect.Height <= 0) return null;

            Bitmap result = new Bitmap(rect.Width, rect.Height);
            Graphics g = Graphics.FromImage(result);

            double dx = (rect.Width / ext.Width);
            double dy = (rect.Height / ext.Height);

            double[] a = this._worldFile.Affine;

            // gets the affine scaling factors.
            float m11 = Convert.ToSingle(a[1] * dx);
            float m22 = Convert.ToSingle(a[5] * -dy);
            float m21 = Convert.ToSingle(a[2] * dx);
            float m12 = Convert.ToSingle(a[4] * -dy);
            float l = (float)(a[0] - .5 * (a[1] + a[2])); // Left of top left pixel
            float t = (float)(a[3] - .5 * (a[4] + a[5])); // top of top left pixel
            float xShift = (float)((l - ext.MinX) * dx);
            float yShift = (float)((ext.MaxY - t) * dy);
            g.Transform = new Matrix(m11, m12, m21, m22, xShift, yShift);

            g.DrawImage(this._innerImage, new Point(0, 0));
            g.Dispose();

            return result;
        }
        


        # endregion

    }
}
